﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DeliciousTransform
{
    class Program
    {
        static void Exit()
        {
            Console.WriteLine();
            Console.WriteLine("Press any key to exit.");
            Console.ReadKey();
            Environment.Exit(0);
        }

        static string Warning(string c, string str)
        {
            // These errors should be sent somewhere other than Console since
            // it is hard to capture all of them there.

            // Convert occurances of the 'c' character with spaces.
            // Filenames in Windows cannot use the 'c' character.
            // The IE import of the test bookmark file performed this
            // substition without reporting any errors or warnings to the
            // user.
            if (str.Contains(c))
            {
                Console.Write("WARNING: Replacing '" + c + "' with spaces in \t");
                Console.WriteLine(str);                
                str = str.Replace(c, " ");
            }

            return str;
        }

        static Bookmark GetRecord(string line, System.Collections.Hashtable names)
        {
            // The field validation logic should probably be refactored from here
            // to the setter methods in the Bookmark class.

            Bookmark b = new Bookmark();

            // URL
            int url_begin = line.IndexOf("<DT><A HREF=\"") + "<DT><A HREF=\"".Length;
            line = line.Substring(url_begin);
            int url_end = line.IndexOf("\"");
            string url = line.Substring(0, url_end);
            b.URL = url;

            // Add Date
            int add_begin = line.IndexOf(" ADD_DATE=\"") + " ADD_DATE=\"".Length;
            line = line.Substring(add_begin);
            int add_end = line.IndexOf("\"");
            string add_date = line.Substring(0, add_end);
            b.AddDate = add_date;

            // Private
            int private_begin = line.IndexOf(" PRIVATE=\"") + " PRIVATE=\"".Length;
            line = line.Substring(private_begin);
            int private_end = line.IndexOf("\"");
            string private_val = line.Substring(0, private_end);
            b.Private = private_val;

            // Tags
            int tags_begin = line.IndexOf(" TAGS=\"") + " TAGS=\"".Length;
            line = line.Substring(tags_begin);
            int tags_end = line.IndexOf("\"");
            string tag_set = line.Substring(0, tags_end);
            char[] delimiterChars = { ',' };
            string[] tags = tag_set.Split(delimiterChars);
            for (int i = 0; i < tags.Length; i++)
            {
                tags[i] = Warning("<strong>", tags[i]);
                tags[i] = Warning("|", tags[i]);
                tags[i] = Warning("?", tags[i]);
                tags[i] = Warning("/", tags[i]);
                tags[i] = Warning(":", tags[i]);
                tags[i] = Warning("\"", tags[i]);
                tags[i] = Warning(">", tags[i]);
                tags[i] = Warning("\\", tags[i]);
                tags[i] = Warning("*", tags[i]);
            }
            b.Tags = tags;

            // Name
            int name_begin = line.IndexOf(">") + ">".Length;
            line = line.Substring(name_begin);
            int name_end = line.IndexOf("</A>");
            string name = line.Substring(0, name_end);

            name = Warning("<strong>", name);
            name = Warning("|", name);
            name = Warning("?", name);
            name = Warning("/", name);
            name = Warning(":", name);
            name = Warning("\"", name);
            name = Warning(">", name);
            name = Warning("\\", name);
            name = Warning("*", name);

            // If this name already exists add a suffix of (Imported).
            // This is what IE did with the test input file, however
            // IE did not report any errors or warnings. Note that this
            // technique will fail if there are 3 occurances of identical
            // names in the input file.
            if (names.ContainsKey(name))
            {
                Console.Write("WARNING: Adding \" (Imported)\" to 2nd occurance of \t" + name);
                name = name + " (Imported)";
            }

            // The IE test case simply did not import records with names having more
            // than 260 characters. IE did not report any warnings or errors.
            if (name.Length > 215)
            {
                Console.Write("WARNING: Only the 1st 215 characters were kept from \t" + name);
                name = name.Substring(0, 200);
            }

            b.Name = name;
            names.Add(name, "1");

            return b;
        }

        static void TestLine(int linenum, string actual, string expected)
        {
            if (actual.CompareTo(expected) != 0)
            {
                Console.Write("Unexpected text in line ");
                Console.Write(linenum);
                Console.WriteLine(" of input file.");

                Console.WriteLine("Expected: ");
                Console.WriteLine(expected);

                Console.WriteLine("Received: ");
                Console.WriteLine(actual);

                Exit();
            }

            return;
        }

        static void Main(string[] args)
        {
            string[] lines = System.IO.File.ReadAllLines(@"\Data\delicious.html");

            TestLine(1, lines[0], "<!DOCTYPE NETSCAPE-Bookmark-file-1>");
            TestLine(2, lines[1], "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=UTF-8\">");
            TestLine(3, lines[2], "<!-- This is an automatically generated file.");
            TestLine(4, lines[3], "It will be read and overwritten.");
            TestLine(5, lines[4], "Do Not Edit! -->");
            TestLine(6, lines[5], "<TITLE>Bookmarks</TITLE>");
            TestLine(7, lines[6], "<H1>Bookmarks</H1>");
            TestLine(8, lines[7], "<DL><p>");

            bool ddmode = false;
            int linenum = 8;
            System.Collections.ArrayList bookmarks = new System.Collections.ArrayList();
            System.Collections.Hashtable names = new System.Collections.Hashtable();

            for (; linenum < lines.Length; linenum++)
            {
                string linetype = lines[linenum].Substring(0, 4);

                switch (linetype)
                {
                    case "<DT>":
                        ddmode = false;

                        Bookmark b = GetRecord(lines[linenum], names);
                        bookmarks.Add(b);

                        break;

                    case "<DD>":
                        ddmode = true;

                        string description = lines[linenum].Substring(4);
                        Bookmark b2 = (Bookmark)bookmarks[bookmarks.Count - 1];
                        b2.Description = description;
                        bookmarks[bookmarks.Count - 1] = b2;

                        break;

                    case "</DL":
                        ddmode = false;

                        break;

                    default:
                        if (ddmode)
                        {
                            // Add to description string.
                            string desc2 = lines[linenum];
                            Bookmark b3 = (Bookmark)bookmarks[bookmarks.Count - 1];
                            b3.Description += "\n" + desc2;
                            bookmarks[bookmarks.Count - 1] = b3;
                        }
                        else
                        {
                            TestLine(linenum + 1, linetype, "<DT>");
                        }
                        break;
                }
            }

            Console.WriteLine("Read " + bookmarks.Count + " records.");

            foreach (Bookmark favorite in bookmarks)
            {
                favorite.Save();
            }

            Console.WriteLine("Processed " + linenum + " lines.");

            Exit();
        }
    }
}
